package uk.ac.ebi.microarray.expressionprofiler.ra.fs.impl;

import java.io.File;
import java.io.PrintWriter;
import java.util.Set;

import javax.resource.ResourceException;
import javax.resource.spi.ConnectionManager;
import javax.resource.spi.ConnectionRequestInfo;
import javax.resource.spi.ManagedConnection;
import javax.resource.spi.ManagedConnectionFactory;
import javax.resource.spi.ResourceAdapter;
import javax.resource.spi.ResourceAdapterAssociation;
import javax.resource.spi.work.WorkManager;
import javax.security.auth.Subject;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import uk.ac.ebi.microarray.expressionprofiler.ra.AEEPResourceAdapter;

public class FileSystemManagedConnectionFactory implements ManagedConnectionFactory, ResourceAdapterAssociation {

    private static final long serialVersionUID = -5371227665508027514L;

    private final Log log = LogFactory.getLog(FileSystemManagedConnectionFactory.class);

    private AEEPResourceAdapter ra;

    private transient PrintWriter writer;

    private String repository;
    private int parallelFtpConnection;

    private void checkProperties() throws ResourceException {
        if (repository == null) {
            throw new ResourceException("Path to a repository is null");
        }

        File rep = new File(repository);
        if (!rep.exists() || !rep.isDirectory()) {
            throw new ResourceException("Path [" + rep.getAbsolutePath() + "] does not lead to a repository");
        }
    }

    public Object createConnectionFactory(ConnectionManager cm) throws ResourceException {
        log.info("createConnectionFactory, cm=" + cm);
        return new FileSystemConnectionFactoryImpl(this, cm);
    }

    public Object createConnectionFactory() throws ResourceException {
        log.info("createConnectionFactory");
        return new FileSystemConnectionFactoryImpl(this, null);
    }

    public ManagedConnection createManagedConnection(Subject subj, ConnectionRequestInfo conReqInfo)
            throws ResourceException {
        log.info("createManagedConnection, subj=" + subj + ", conReqInfo=" + conReqInfo);
        checkProperties();
        return new FileSystemManagedConnection(conReqInfo, writer, this);
    }

    @SuppressWarnings("unchecked")
    public ManagedConnection matchManagedConnections(Set set, Subject subj, ConnectionRequestInfo conReqInfo)
            throws ResourceException {
        log.info("matchManagedConnections, set=" + set + ", subj=" + subj + ", conReqInfo=" + conReqInfo);
        for (Object obj : set) {
            if (obj instanceof FileSystemManagedConnection) {
                return (FileSystemManagedConnection) obj;
            }
        }
        return null;
    }

    public void setLogWriter(PrintWriter out) throws ResourceException {
        log.info("setLogWriter " + out);
        this.writer = out;
    }

    public PrintWriter getLogWriter() throws ResourceException {
        return writer;
    }

    @Override
    public int hashCode() {
        if (repository == null) {
            return super.hashCode();
        } else {
            return repository.hashCode();
        }
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (!(obj instanceof FileSystemManagedConnectionFactory)) {
            return false;
        }
        if (repository == null) {
            return false;
        }
        return repository.equals(((FileSystemManagedConnectionFactory) obj).getRepositoryPath());
    }

    public String getRepositoryPath() {
        return repository;
    }

    public void setRepositoryPath(String path) {
        log.info("RepositoryPath: " + path);
        this.repository = path;
    }

    public Integer getParallelFtpConnection() {
        return parallelFtpConnection;
    }

    public void setParallelFtpConnection(Integer parallelFtpConnection) {
        log.info("ParallelFtpConnection: " + parallelFtpConnection);
        this.parallelFtpConnection = parallelFtpConnection;
    }

    public ResourceAdapter getResourceAdapter() {
        log.info("getResourceAdapter");
        return ra;
    }

    public void setResourceAdapter(ResourceAdapter ra) throws ResourceException {
        log.info("setResourceAdapter " + ra);
        this.ra = (AEEPResourceAdapter) ra;
    }

    public WorkManager getWorkManager() {
        return (ra != null) ? ra.getWorkManager() : null;
    }
}
